#include "wifi_adapter.h"
#include "iot_uart.h"
#include "queue.h"
#include "stdio.h"
#include "string.h"
#include "stdint.h"

extern QueueInfo g_queueInfo[QUEUE_MAX];
extern uint8_t g_wifiEventQueue;
extern NetModeType g_wifiMode;
uint8_t g_clientQueue = 0xff;

void HotspotChangeCB(WifiErrorCode res)
{
    if (g_wifiEventQueue != 0xff){
        // 遍历队列
        QUEUE_NODE *tmp;
        // 遍历
        uint16_t i = 0;
        LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[g_wifiEventQueue].head, QUEUE_NODE, s_list){
            // 检测指针
            if(((WifiEvent *)(tmp->user_data))->OnHotspotStateChanged == NULL)
                continue;
            if (res == WIFI_SUCCESS)
                ((WifiEvent *)(tmp->user_data))->OnHotspotStateChanged(WIFI_STATE_AVAILABLE);
            else
                ((WifiEvent *)(tmp->user_data))->OnHotspotStateChanged(WIFI_STATE_NOT_AVAILABLE);
        }
    }
}
void HotspotStaJoinCB(StationInfo *info)
{
    if (g_wifiEventQueue != 0xff){
        // 遍历队列
        QUEUE_NODE *tmp;
        // 遍历
        uint16_t i = 0;
        LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[g_wifiEventQueue].head, QUEUE_NODE, s_list){
            // 检测指针
            if(((WifiEvent *)(tmp->user_data))->OnHotspotStaJoin == NULL)
                continue;
            ((WifiEvent *)(tmp->user_data))->OnHotspotStaJoin(info);
        }
    }
}
void HotspotStaLeaveCB(StationInfo *info)
{
    if (g_wifiEventQueue != 0xff){
        // 遍历队列
        QUEUE_NODE *tmp;
        // 遍历
        uint16_t i = 0;
        LOS_DL_LIST_FOR_EACH_ENTRY(tmp, &g_queueInfo[g_wifiEventQueue].head, QUEUE_NODE, s_list){
            ((WifiEvent *)(tmp->user_data))->OnHotspotStaLeave(info);
        }
    }
}
/**
 * @brief Enables the hotspot mode.
 *
 * Before using this function, you need to invoke {@link SetHotspotConfig} and set at least the SSID, security type,
 * and key. \n
 *
 * @return Returns {@link WIFI_SUCCESS} if the hotspot mode is enabled; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode EnableHotspot(void)
{
    WifiErrorCode res;
    // 设置模式3 这是esp8266的station+ap模式
    char mode = 3;
    res = SendWifiCommand(WIFI_SET_MODE, &mode);
    if (res == WIFI_SUCCESS){
        res = WaitWifiResponse(WIFI_SET_MODE, &g_wifiMode, WIFI_TIMEOUT);
    }
    if (res == WIFI_SUCCESS){
        // 创建队列
        if (g_clientQueue == 0xff)
            // 12:34:56:78:90:12,192.168.123.234,00,client1
            QueueCreate(&g_clientQueue, sizeof(ClientInfo), WIFI_MAX_STA_NUM);
    }
    // 回调函数
    HotspotChangeCB(res);
    return res;
}

/**
 * @brief Disables the hotspot mode.
 *
 * @return Returns {@link WIFI_SUCCESS} if the hotspot mode is disabled; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode DisableHotspot(void)
{
    WifiErrorCode res;
    // 设置模式1 这是esp8266的station模式
    char mode = 1;
    
    res = SendWifiCommand(WIFI_SET_MODE, &mode);
    if (res == WIFI_SUCCESS){
        res = WaitWifiResponse(WIFI_SET_MODE, &g_wifiMode, WIFI_TIMEOUT);
    }
    
    if (res == WIFI_SUCCESS){
        QueueDestroy(g_clientQueue);
    }
    // 回调函数
    HotspotChangeCB(res);
    return res;
}

/**
 * @brief Sets a specified hotspot configuration.
 *
 * The hotspot configuration includes the SSID, security type, and key. The configuration set overwrites the existing
 * configuration and takes effect after the hotspot mode is re-enabled. \n
 * Before enabling the hotspot mode for the first time, you must call this function. \n
 *
 * @param config Indicates the hotspot configuration to set.
 * @return Returns {@link WIFI_SUCCESS} if the hotspot configuration is set; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode SetHotspotConfig(const HotspotConfig *config)
{
    WifiErrorCode res;
    // 发送指令
    
    res = SendWifiCommand(AP_SET_PARAM, config);
    if (res == WIFI_SUCCESS){
        res = WaitWifiResponse(AP_SET_PARAM, NULL, WIFI_TIMEOUT);
    }
    
    return res;
}

/**
 * @brief Obtains a specified hotspot configuration.
 *
 * The hotspot configuration includes the SSID, security type, and key. \n
 *
 * @param result Indicates the obtained hotspot configuration.
 * @return Returns {@link WIFI_SUCCESS} if the hotspot configuration is obtained; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetHotspotConfig(HotspotConfig *result)
{
    WifiErrorCode res;

    // 参数不能为空
    if (result == NULL)
        return ERROR_WIFI_INVALID_ARGS;
    // 发送指令并等待应答
    
    res = SendWifiCommand(AP_GET_PARAM, NULL);
    if (res == WIFI_SUCCESS){
        res = WaitWifiResponse(AP_GET_PARAM, result, WIFI_TIMEOUT);
    }
    
    return res;
}

/**
 * @brief Checks whether the hotspot mode is enabled.
 *
 * @return Returns {@link WIFI_HOTSPOT_ACTIVE} if the hotspot mode is enabled; returns {@link WIFI_HOTSPOT_NOT_ACTIVE}
 * otherwise.
 * @since 7
 */
int IsHotspotActive(void)
{
    if (g_wifiMode == ATA_AP)
        return WIFI_HOTSPOT_ACTIVE;
    return WIFI_HOTSPOT_ACTIVE;
}

/**
 * @brief Obtains an array of stations connected to this hotspot.
 *
 * The station information is defined in {@link StationInfo}. \n
 *
 * @param result Indicates the array of stations connected to this hotspot. The array is requested and released by the
 * caller. The value must be greater than or equal to {@link WIFI_MAX_STA_NUM}.
 * @param size Indicates the size of the array.
 * @return Returns {@link WIFI_SUCCESS} if the array of stations connected to this hotspot is obtained; returns an error
 *  code defined in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetStationList(StationInfo *result, unsigned int *size)
{
    WifiErrorCode res;

    // 无效参数
    if (result == NULL)
        return ERROR_WIFI_INVALID_ARGS;
    // 获取终端列表
    res = SendWifiCommand(AP_LIST_CLIENT, NULL);
    if (res == WIFI_SUCCESS){
        res = WaitWifiResponse(AP_LIST_CLIENT, result, WIFI_TIMEOUT);
    }
    else
        return res;
    // 信息个数
    *size = g_queueInfo[g_clientQueue].cur_len;
    // 逐条获取
    for (uint8_t i = 0; i < (*size); i++){
        ClientInfo info;
        // 出队
        QueueOut(g_clientQueue, (char *)(&info));
        result[i].ipAddress = info.ipAddress;
        memcpy(result[i].macAddress, info.macAddress, 6);
        result[i].disconnectedReason = info.disconnectedReason;
        uint8_t name_len = strlen(info.name);
        result[i].name = (char *)malloc(name_len+1);
        if (result[i].name != NULL){
            memset(result[i].name, 0, name_len+1);
            memcpy(result[i].name, info.name, name_len);
        }
    }
    return res;
}
/**
 * @brief Disconnects from the station with a specified MAC address.
 *
 * @param mac Indicates the pointer to the MAC address of the station.
 * @param macLen Indicates the length of the MAC address of the station.
 * @return Returns {@link WIFI_SUCCESS} if the function is successfully called;
 * returns an error code defined in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode DisassociateSta(unsigned char *mac, int macLen)
{
    // AT+CWQIF 不支持该指令
    return ERROR_WIFI_NOT_SUPPORTED;
}

/**
 * @brief Adds the hotspot transmit power to the beacon.
 *
 * After the transmit power is added, the beacon must contain specified IEs. If the minimum transmit power
 * <b>0xFFFFFFFF</b> is added, the beacon does not contain the IEs. \n
 * The transmit power is added to the <b>ie</b> field only, exerting no impacts on the transmit power. \n
 * @param power Indicates the transmit power to add.
 * @return Returns {@link WIFI_SUCCESS} if the function is successfully called; returns an error code defined
 * in {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode AddTxPowerInfo(int power)
{
    return WIFI_SUCCESS;
}

/**
 * @brief Sets the frequency band for this hotspot.
 *
 * @param band Indicates the frequency band to set.
 * @return Returns {@link WIFI_SUCCESS} if the frequency band is set; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode SetBand(int band)
{
    if (band == HOTSPOT_BAND_TYPE_2G)
        return WIFI_SUCCESS;
    return ERROR_WIFI_NOT_SUPPORTED;
}

/**
 * @brief Obtains the frequency band of this hotspot.
 *
 * @param result Indicates the obtained frequency band.
 * @return Returns {@link WIFI_SUCCESS} if the frequency band is obtained; returns an error code defined in
 * {@link WifiErrorCode} otherwise.
 * @since 7
 */
WifiErrorCode GetBand(int *result)
{
    *result = HOTSPOT_BAND_TYPE_2G;
    return WIFI_SUCCESS;
}
